package com.hirsi.common.core.interceptor;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWTException;
import cn.hutool.jwt.JWTUtil;
import com.hirsi.common.core.annotation.IgnoreAccessTokenValid;
import com.hirsi.common.module.auth.enums.AuthExceptionStatusEnum;
import com.hirsi.common.core.constant.HeaderConstant;
import com.hirsi.common.core.constant.RedisConstant;
import com.hirsi.common.core.exception.ServerRuntimeException;
import com.hirsi.common.core.util.AccessTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 令牌拦截器
 */
@Slf4j
@Component
public class AccessTokenHandlerInterceptor implements IHandlerInterceptor {

    @Value("${ztk.jwt_key}")
    private String jwtKey;

    @Value("${spring.application.name:#{''}}")
    private String applicationName;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        if (handler instanceof HandlerMethod) {
            IgnoreAccessTokenValid ignoreAccessTokenValid = ((HandlerMethod) handler).getMethodAnnotation(IgnoreAccessTokenValid.class);
            if (ignoreAccessTokenValid != null) return true;
            String accessToken = request.getHeader(HeaderConstant.ACCESS_TOKEN);
            if (StrUtil.isNotBlank(accessToken)) {
                try {
                    if (JWTUtil.verify(accessToken, jwtKey.getBytes())) {
                        Integer userId = AccessTokenUtil.getUserId();
                        String s = redisTemplate.opsForValue().get(String.format(RedisConstant.ACCESS_TOKEN_KEY_PREFIX, applicationName, userId));
                        if (StrUtil.isBlank(s) || !s.equals(accessToken)) throw new ServerRuntimeException(AuthExceptionStatusEnum.TOKEN_INVALID);
                        return true;
                    }
                } catch (JWTException e) {
                    throw new ServerRuntimeException(AuthExceptionStatusEnum.TOKEN_INVALID);
                }
            }
            throw new ServerRuntimeException(AuthExceptionStatusEnum.TOKEN_INVALID);
        }
        return true;
    }

    @Override
    public String[] addPaths() {
        return new String[] {"/**"};
    }

    @Override
    public String[] excludePaths() {
        return new String[0];
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
